package com.brunogb.pages.database.repository;

import java.util.List;

import javax.jdo.PersistenceManager;

import org.apache.commons.lang.math.NumberUtils;


import com.brunogb.pages.database.PMF;
import com.brunogb.pages.exceptions.RepositoryException;
import com.brunogb.pages.server.model.BaseModel;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Query;

/**
 * @author jairo
 *
 */
@SuppressWarnings("all")
public abstract class BaseRepository<T> {

	protected PersistenceManager manager = PMF.getPMF().getPersistenceManager();
	
	/**
	 * 
	 * @param model
	 * @return
	 */
	public T save(T model) throws RepositoryException {
		try {
			return manager.makePersistent(model);
		} catch (Exception e) {
			throw new RepositoryException("Erro ao persitir o objeto.", e);
		}
	}
	
	/**
	 * 
	 * @param model
	 * @throws RepositoryException
	 */
	public void remove(T model) throws RepositoryException {
		try {
			manager.deletePersistent(model);
		} catch (Exception e) {
			throw new RepositoryException("Erro ao remover o objeto.", e);
		}
	}
	
	/**
	 * 
	 * @param clazz
	 * @return
	 * @throws RepositoryException
	 */
	protected int count(Class<? extends BaseModel> clazz) throws RepositoryException {
		try {
			return DatastoreServiceFactory.getDatastoreService()
							.prepare(new Query(clazz.getSimpleName())).countEntities();
		} catch (Exception e) {
			throw new RepositoryException("Erro ao obter a quantidade de objetos no Datastore.", e);
		}
	}
	
	/**
	 * 
	 * @param id
	 * @param clazz
	 * @return
	 * @throws RepositoryException
	 */
	protected T find(Object id, Class<? extends BaseModel> clazz) throws RepositoryException {
		try {
			Key key = null;
			String idValue = id.toString();
			if (NumberUtils.isNumber(idValue)) {
				key = KeyFactory.createKey(clazz.getSimpleName(), Integer.parseInt(idValue));
			} else {
				key = KeyFactory.createKey(clazz.getSimpleName(), idValue);
			}
			return (T) manager.getObjectById(clazz, key);
		} catch (Exception e) {
			throw new RepositoryException("Erro ao recuperar o objeto.", e);
		}
	}
	
	/**
	 * 
	 * @param id
	 * @param clazz
	 * @return
	 * @throws RepositoryException
	 */
	protected T find(Key id, Class<? extends BaseModel> clazz) throws RepositoryException {
		try {
			return (T) manager.getObjectById(clazz, id);
		} catch (Exception e) {
			throw new RepositoryException("Erro ao recuperar o objeto.", e);
		}
	}
	
	/**
	 * 
	 * @param clazz
	 * @return
	 * @throws RepositoryException
	 */
	protected List<T> findAll(Class<? extends BaseModel> clazz) throws RepositoryException {
		try {
			return (List<T>) manager.newQuery(clazz).execute();
		} catch (Exception e) {
			throw new RepositoryException("Erro ao recuperar todos os objetos.", e);
		}
	}
	
	/**
	 * 
	 * @return
	 * @throws RepositoryException
	 */
	public abstract int count() throws RepositoryException;
	
	/**
	 * 
	 * @param id
	 * @return
	 * @throws RepositoryException
	 */
	public abstract T find(Object id) throws RepositoryException;
	
	/**
	 * 
	 * @param id
	 * @return
	 * @throws RepositoryException
	 */
	public abstract T find(Key id) throws RepositoryException;
	
	/**
	 * 
	 * @return
	 * @throws RepositoryException
	 */
	public abstract List<T> findAll() throws RepositoryException;
		
}
